package com.gopay.checkorder.service.impl;

import java.math.BigDecimal;
import java.util.List;

import javax.annotation.Resource;
import javax.naming.CommunicationException;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.gopay.checkorder.manager.BankOrderManager;
import com.gopay.checkorder.manager.OrderAdRecordManager;
import com.gopay.checkorder.service.CheckGopayOrderService;
import com.gopay.common.constants.order.CheckOrderJoin;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.TxnStaCode;
import com.gopay.common.cps.manager.order.CpsGeneralMainOrderQueryManager;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.cashier.BankCardType;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cps.CpsOrderAdjustRecord;
import com.gopay.common.domain.cps.vo.CheckOrderResult;
import com.gopay.common.domain.cps.vo.InAccInfo;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.DateUtils;

/**
 * 国付宝对单接口实现
 * 
 * @CheckGopayOrderServiceImpl.java
 * @author yaobo
 * @2013-11-6 下午02:25:46 www.gopay.com.cn Inc.All rights reserved.
 */
@Service("checkGopayOrderService")
public class CheckGopayOrderServiceImpl implements CheckGopayOrderService {
    private final static Logger logger = LoggerFactory.getLogger("CHECK_GOPAY_ORDER");

    @Resource(name = "bankOrderManager")
    private BankOrderManager bankOrderManager;

    @Resource(name = "orderAdRecordManager")
    private OrderAdRecordManager recordManager;

    @Resource(name = "cpsGeneralMainOrderQueryManager")
    private CpsGeneralMainOrderQueryManager mainOrderQuery;

    @Override
    public boolean isexist(String[] gopayOrderIds, BigDecimal[] amts) throws GopayException {
        if (gopayOrderIds == null || gopayOrderIds.length == 0) {
            return false;
        }

        String gopayOrderId = "";
        BigDecimal amt = null;
        BankOrder bankOrder = null;
        CpsGenMainOrder mainOrder = null;
        for (int i = 0; i < gopayOrderIds.length; i++) {
            gopayOrderId = gopayOrderIds[i];
            amt = amts[i];

            bankOrder = bankOrderManager.getByGopayOutOrderId(gopayOrderId);
            if (bankOrder == null) {
                logger.error(gopayOrderId + "对单失败 " + ProcCodeConstants.PROC_CODE_100E5060);
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E5060, gopayOrderId);
            }

            mainOrder = mainOrderQuery.get(bankOrder.getOrderId());
            if (mainOrder == null || mainOrder.getTotalOrderAmt() == null
                    || mainOrder.getOrderDealAmt().compareTo(amt) != 0) {
                logger.error(gopayOrderId + "对单失败 " + ProcCodeConstants.PROC_CODE_200E1014);
                throw new GopayException(ProcCodeConstants.PROC_CODE_200E1014, gopayOrderId);
            }
        }

        return true;
    }

    @Override
    public CheckOrderResult checkOrder(String gopayOutOrderId, String operId) throws GopayException {
        if (StringUtils.isBlank(gopayOutOrderId)) {
            // 银行订单号为空
            logger.error("对单失败 " + ProcCodeConstants.PROC_CODE_100E5096 + "银行订单号为空");
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E5096);
        }

        if (StringUtils.isBlank(operId)) {
            // 操作员为空
            logger.error(gopayOutOrderId + "对单失败 " + ProcCodeConstants.PROC_CODE_100E5097 + "操作员为空");
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E5097);
        }

        CpsOrderAdjustRecord record = recordManager.get(gopayOutOrderId);
        if (record == null) {
            // 订单调整记录不存在
            logger.error(gopayOutOrderId + "对单失败 " + ProcCodeConstants.PROC_CODE_100E5093);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E5093);
        }

        // 设置手工点击对账操作者
        record.setManualAdjustOperId(operId);

        return checkOrder(record, CheckOrderJoin.CONSOLE);
    }

    @Override
    public CheckOrderResult checkOrder(CpsOrderAdjustRecord record, CheckOrderJoin join) throws GopayException {
        CheckOrderResult result = new CheckOrderResult();

        if (record == null) {
            // 订单调整记录不存在
            logger.error("订单调整记录不存在 " + ProcCodeConstants.PROC_CODE_100E5093);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E5093);
        }

        if (join == null) {
            // 发起方为空
            logger.error("发起方为空 " + ProcCodeConstants.PROC_CODE_100E5094);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E5094);
        }

        if (recordManager.lock(record.getGopayOutOrderId()) == 0) {
            // 锁定失败
            logger.error(record.getGopayOutOrderId() + "锁定失败 " + ProcCodeConstants.PROC_CODE_100E5095);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E5095);
        }

        // 获取银行流水
        BankOrder bankOrder = bankOrderManager.getByGopayOutOrderId(record.getGopayOutOrderId());
        if (bankOrder == null) {
            // 银行流水不存在
            result.setErrCode(ProcCodeConstants.PROC_CODE_100E5060);
            record.setAdjustResult(CpsOrderAdjustRecord.AdjustResult.BANKORDER_NULL.value);
            logger.error(record.getGopayOutOrderId() + " 银行流水不存在" + ProcCodeConstants.PROC_CODE_100E5060);

            recordManager.update(record, join);
            return result;
        }

        // 获取订单
        CpsGenMainOrder mainOrder = mainOrderQuery.get(bankOrder.getOrderId());
        if (mainOrder == null) {
            // 订单不存在
            result.setErrCode(ProcCodeConstants.PROC_CODE_100E5041);
            record.setAdjustResult(CpsOrderAdjustRecord.AdjustResult.BANKORDER_NULL.value);
            logger.error("订单:" + record.getGopayOrderId() + " 银行订单:" + record.getGopayOutOrderId() + " 订单不存在 "
                    + ProcCodeConstants.PROC_CODE_100E5041);

            recordManager.update(record, join);
            return result;
        }

        // 设置国付宝订单号、交易金额、订单状态
        record.setGopayOrderId(mainOrder.getGopayOrderId());
        record.setBankRecordAmt(mainOrder.getTotalOrderAmt());
        record.setOrigOrderStatus(mainOrder.getTxnStaCd());
        record.setAdjustResult(CpsOrderAdjustRecord.AdjustResult.FAIL.value);
        record.setAdjustTime(DateUtils.getSystemDate());
        record.setLastUpdTime(DateUtils.getSystemDate());

        result.setAmount(mainOrder.getTotalOrderAmt());
        result.setOrderId(mainOrder.getGopayOrderId());

        if (mainOrder.getTxnStaCd() == TxnStaCode.TXN_STA_CD_20000.value) {
            // 订单已处理成功，不处理
            record.setAdjustResult(CpsOrderAdjustRecord.AdjustResult.NO_PROCESS.value);
            result.setSuccess(true);
            recordManager.update(record, join);

            logger.error("订单:" + record.getGopayOrderId() + " 银行订单:" + record.getGopayOutOrderId() + " 订单已处理成功，不处理");
            return result;
        }

        // 入账
        InAccInfo accInfo = new InAccInfo();
        accInfo.setOrderId(bankOrder.getOrderId());
        accInfo.setAmount(mainOrder.getTotalOrderAmt());
        accInfo.setRetCode("00");
        accInfo.setCardType(BankCardType.Unknown.toString());
        result.setAccInfo(accInfo);

        try {
            if (!bankOrderManager.inAcct(result)) {
                // 入账失败
                result.setErrCode(ProcCodeConstants.PROC_CODE_100E6020);
                logger.error("订单:" + record.getGopayOrderId() + " 银行订单:" + record.getGopayOutOrderId() + " 入账失败"
                        + ProcCodeConstants.PROC_CODE_100E6020);

                recordManager.update(record, join);
                return result;
            }

            // 入账成功
            record.setAdjustResult(CpsOrderAdjustRecord.AdjustResult.SUCCESS.value);
            result.setSuccess(true);
            recordManager.update(record, join);

            logger.error("订单:" + record.getGopayOrderId() + " 银行订单:" + record.getGopayOutOrderId() + "入账成功");
        } catch (CommunicationException e) {
            // 系统内远程调用超时
            result.setErrCode(ProcCodeConstants.PROC_CODE_200F3001);
            logger.error("订单号:" + record.getGopayOutOrderId() + " 银行订单号:" + record.getGopayOrderId() + " 系统异常", e);

            recordManager.update(record, join);
            return result;
        }

        return result;
    }

    @Override
    public List<CpsOrderAdjustRecord> getUnCheckList(String adjustResult, int adjustCounts, int pageIndex, int pageSize) {
        return recordManager.getUnCheckList(adjustResult, adjustCounts, pageIndex, pageSize);
    }

    @Override
    public int getUnCheckCount(String adjustResult, int adjustCounts) {
        return recordManager.getUnCheckCount(adjustResult, adjustCounts);
    }

}
